package com.whjz.filter;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.ServletInputStreamWrapper;

import com.whjz.redis.RedisUtils;
import com.whjz.utils.CodeUtil;
import com.whjz.utils.ResultUtil;
import com.whjz.utils.StringConstantUtil;
import com.whjz.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.servlet4preview.http.HttpServletRequestWrapper;
import org.apache.commons.codec.binary.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.*;

/**
 * @author liweibin
 *   公共参数处理方法
 */
@Slf4j
@Component
public class ParamsFilter extends ZuulFilter{

    /**
     * pre 可以在请求被路由之前调用
     * route 在路由请求时被调用
     * post 在route和error过滤之后被调用
     * error 处理请求时发生错误时被调用
     * @return
     */

    @Autowired
    private Environment environment;		// add by liweibin for (TASK)206工单业务加强验证防重复  20190221

    @Override
    public String filterType() {
        return "pre";   //请求路由前调用
    }

    @Override
    public int filterOrder() {
        return 0;   //执行顺序 数字越大级别越低
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
       /* log.info("=================>本次访问进入网关记录时间开始"+System.currentTimeMillis());*/
        RequestContext ctx = RequestContext.getCurrentContext();		//获取请求上下文
        ctx.getResponse().setCharacterEncoding("UTF-8");				//设置编码
        HttpServletRequest request = ctx.getRequest();
        MultipartHttpServletRequest multipartRequest=null;
        log.info("\n==========begin=========url="+request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+request.getRequestURI());
        try {
            request.setCharacterEncoding("UTF-8");
            String contentType  =  request.getContentType();
            if(org.apache.commons.lang3.StringUtils.isNotBlank(contentType) && contentType.contains("multipart")){
                //在如下过滤器中，上传文件中的content-type:multipart/form-data使用获取request.getParameter(key)无法获取相应的值。
                // 需要借助Spring框架中的CommonsMultipartResolver.resolveMultipart(HttpServletRequest request)
                // 将request转为MultipartHttpServletRequest，从而使用getParameter(key)方法获取指定的值
                HttpServletRequest httpRequest = (HttpServletRequest) request;
                contentType = httpRequest.getContentType();
                MultipartResolver resolver = new CommonsMultipartResolver(httpRequest.getSession().getServletContext());
                multipartRequest = resolver.resolveMultipart(httpRequest);
                String logseq = StringUtils.getUUID();
                ctx.addZuulRequestHeader("logseq",logseq);
                String[] custNo = multipartRequest.getParameterValues("custNo");
                if(custNo!=null&&custNo.length==0){

                }
                String[] userId = multipartRequest.getParameterValues("userId");
               if(custNo!=null){
                   ctx.addZuulRequestHeader("custNo",custNo[0]);
               }
               if(userId!=null){
                   ctx.addZuulRequestHeader("userId",userId[0]);
               }

                //}else if(userId!=null){
                    //ctx.addZuulRequestHeader("userId",userId[0]);
               // }
                /*log.info("=======>+文件上传："+request.getRequestURL());*/
                return  null;
            }
        } catch (Exception e) {
            log.info("===1：==>"+e.getMessage());
        }

        //temp  进行视频相关接口释放
        try {
            //获取请求中的参数体
            String reqBody = StreamUtils.copyToString((InputStream) request.getInputStream(), Charset.forName("UTF-8"));

            //判断是否包含用form提交的文件数据，有的话直接返回
            if(reqBody.contains("form-data")) {
                return null;
            }

            //签名校验
//            try {
//                String sign = request.getHeader("X-Mgs-Proxy-Signature");//移动网关传过来的签名
//                String salt ="1638b3f3b90c4829aabdaa7db94bfb3c";     //MD5 Salt
//                String stringToSign = getStringToSign(request, reqBody);
//                MessageDigest digest = MessageDigest.getInstance("MD5");
//                String toSignedContent = stringToSign + salt;
//                byte[] content = digest.digest(toSignedContent.getBytes("UTF-8"));
//                String computedSign = Hex.encodeHexString(content);
//                boolean isSignLegal = Objects.equals(sign, computedSign);
//                log.info("签名匹配: "+stringToSign+" : "+isSignLegal);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }

            JSONObject reqJsonObj = null ;

            try {
                reqJsonObj =JSONObject.parseObject(reqBody);		//数据格式化
            } catch (Exception e) {
                log.info("===2：==>"+e.getMessage());
                e.printStackTrace();		//格式化异常
                return null;
            }

            //GET请求没数据
            if(reqJsonObj == null) {
                return null;
            }

            //判断是否已经按照新的参数方式进行传参了
            boolean hasParams = false;
            if(reqJsonObj.get("params") != null) {
                hasParams  = true;
                String paramsStr =String.valueOf(reqJsonObj.get("params"));
                reqJsonObj =JSONObject.parseObject(paramsStr);		//进行剥离params组装
            }
            String logseq = StringUtils.getUUID();
            reqJsonObj.put("logseq", logseq);
            log.info("记录日志流水号为了确认result:"+logseq);
            ctx.addZuulRequestHeader("logseq",logseq);
            String clientSeqNo = reqJsonObj.getString("custNo");		//获取客户号
            reqJsonObj.put("workstationUrl",request.getRequestURL());
            RedisUtils.setKey(StringConstantUtil.FRONT_SEQ+reqJsonObj.getString("custNo"),reqJsonObj.get("seqNo")+"");
            RedisUtils.setKey(StringConstantUtil.WORKSTATION_RUL+reqJsonObj.getString("custNo"),request.getRequestURL()+"");
            //对前端传的baseInfo 设备基础信息进行解析
            Map<String,String> baseInfoMap = null;
            Object baseInfo =  reqJsonObj.get("baseInfo");			//取出基础数据

            if(baseInfo == null) {
                if(reqJsonObj.containsKey("custNo") && org.apache.commons.lang3.StringUtils.isNotBlank(reqJsonObj.getString("custNo"))){
                    reqJsonObj.put("custNo",reqJsonObj.get("custNo"));
                    ctx.addZuulRequestHeader("custNo",reqJsonObj.get("custNo").toString());
               }
               if(reqJsonObj.containsKey("userId") && org.apache.commons.lang3.StringUtils.isNotBlank(reqJsonObj.getString("userId"))){
                   reqJsonObj.put("userId",reqJsonObj.get("userId"));
               }
                //重置新的请求体数据
                    final byte[] reqBodyBytes = reqJsonObj.toString().getBytes();
                    ctx.setRequest(new HttpServletRequestWrapper(request) {
                        @Override
                        public ServletInputStream getInputStream() throws IOException {
                            return new ServletInputStreamWrapper(reqBodyBytes);
                        }

                        @Override
                        public int getContentLength() {
                            return reqBodyBytes.length;
                        }

                        @Override
                        public long getContentLengthLong() {
                            return reqBodyBytes.length;
                        }
                    });
                //设置编码   先释放掉baseInfo的强制验证         以后要加回去
                //ctx.setSendZuulResponse(false);
                //ctx.setResponseBody(JSONObject.fromObject(ResultUtil.resultMap("缺少基础信息数据", "600", null)).toString());
                return null;
            }
            try {
                baseInfoMap = (Map<String, String>) JSONObject.parse(String.valueOf(baseInfo));		//对象转换
                baseInfoMap.remove("ext1");
                baseInfoMap.remove("ext2");
                baseInfoMap.remove("ext3");
                baseInfoMap.remove("ext4");
                baseInfoMap.remove("ext5");

            } catch (Exception e) {
                e.printStackTrace();
                ctx.setSendZuulResponse(false);
                ctx.setResponseBody(JSONObject.toJSONString((ResultUtil.resultMap(CodeUtil.CODE_601.getName(), CodeUtil.CODE_601.getCode(), null))));
                return null;
            }
            reqJsonObj.remove("baseInfo");		//移除
            reqJsonObj.putAll(baseInfoMap);		//对象合并

            //添加消费方交易号
            ctx.addZuulRequestHeader("custNo",reqJsonObj.get("custNo").toString());
            if (reqJsonObj.containsKey("userId")) {
                ctx.addZuulRequestHeader("userId", reqJsonObj.get("userId").toString());
            }
            reqJsonObj.put("beginTime", String.valueOf(new Date().getTime()));		//请求开始时间   add by liweibin for (BUG)488我的卡包里面下挂失败     (TASK)141 完整app请求流水日志  20181218 begin
            log.info("\n======>请求地址："+request.getRequestURI()+"\n日志流水号:"+reqJsonObj.get("logseq")+"\n======>请求体参数："+reqJsonObj);
            /*log.info("=================>本次访问进入网关参数处理结束记录时间"+System.currentTimeMillis());*/
            //判断请求提交是否在短时间内
            String url = request.getRequestURI();					//请求地址
            String deviceId = reqJsonObj.getString("deviceId");		//设备号
            String key = deviceId + "_" + url;						//
            Long limitTime = environment.getProperty("redis.urlFilterTime",Long.class);		//重复提交请求拦截时间
            if(
                    request.getRequestURI().contains("familyManage/familyManageRelieveStopPay") ||	//亲情账户质押解止付维护
                            request.getRequestURI().contains("familyManage/signingFamilyManage") 			//亲情账户签约维护
                    ){
                //判断该设备是否在时间范围内已经请求过
                if(RedisUtils.existKey(key)) {
                    log.info(url + "请求请勿重复提交");
                    ctx.setSendZuulResponse(false);
                    ctx.setResponseBody(JSONObject.toJSONString((ResultUtil.resultMap(CodeUtil.CODE_602.getName(), CodeUtil.CODE_602.getCode(), null))));
                    //return null;
                }else {
                    RedisUtils.setKeyAndCacheTime(key, "exit", limitTime);		//设备请求信息存入redis
                }
            }

            //重置新的请求体数据
            final byte[] reqBodyBytes = reqJsonObj.toString().getBytes();
            ctx.setRequest(new HttpServletRequestWrapper(request) {
                @Override
                public ServletInputStream getInputStream() throws IOException {
                    return new ServletInputStreamWrapper(reqBodyBytes);
                }

                @Override
                public int getContentLength() {
                    return reqBodyBytes.length;
                }

                @Override
                public long getContentLengthLong() {
                    return reqBodyBytes.length;
                }
            });
            return null;

        } catch (IOException e) {
            log.info("\n公共参数处理方法", e);
            ctx.setSendZuulResponse(false);
            ctx.setResponseBody(JSONObject.toJSONString((ResultUtil.resultMap(CodeUtil.CODE_601.getName(), CodeUtil.CODE_601.getCode(), null))));
            return null;
        }
    }

    /**
     * 获取用来签名的字符串
     */
    private String getStringToSign(HttpServletRequest request, String reqBody) throws Exception {
        String httpMethod = request.getMethod().toUpperCase();
        String contentMd5 = getContentMd5(request, reqBody);
        String url = getUrl(request);
        return httpMethod+"\n"+contentMd5+"\n"+url;
    }

    private String getContentMd5(HttpServletRequest request, String reqBody) throws Exception {
        if (!"PUT".equalsIgnoreCase(request.getMethod()) &&
                !"POST".equalsIgnoreCase(request.getMethod())) {
            return "";
        }

        if (request.getContentType() == null || request.getContentType().toLowerCase().startsWith("application/x-www-form-urlencoded")) {
            return "";
        }

        MessageDigest md5 = MessageDigest.getInstance("md5");
        if (Strings.isNullOrEmpty(reqBody)) {
            reqBody = "null";
        }

        return Base64.getEncoder().encodeToString(md5.digest(reqBody.getBytes(Charsets.UTF_8)));
    }

    private String getUrl(HttpServletRequest request) {
        String path = request.getRequestURI();
        List<String> sort = new ArrayList<>();
        Map<String, String> querys = new HashMap<>();
        String[] queryStrings = request.getQueryString() != null?request.getQueryString().split("&"):new String[0];
        for (String queryString:queryStrings) {
            String[] ss = queryString.split("=", 2);
            sort.add(ss[0]);
            querys.put(ss[0], ss[1]);
        }
        sort.sort(String::compareTo);
        String s = "";
        for (String ss:sort) {
            String value = querys.get(ss);
            if (!s.isEmpty()) {
                s += "&";
            }
            s += ss+"="+value;
        }
        return s.isEmpty()?path:path+"?"+s;
    }

    public static void main(String[] args) throws Exception{
//        MessageDigest md5 = MessageDigest.getInstance("md5");
//        byte[] bytes = md5.digest("abc".getBytes(Charsets.UTF_8));
//        String s1 = Base64.getEncoder().encodeToString(bytes);
//        String s2 = org.apache.commons.net.util.Base64.encodeBase64String(bytes);
//        System.out.println(s1+" "+s2);

//        MessageDigest md5 = MessageDigest.getInstance("md5");
//        String ss = org.apache.tomcat.util.codec.binary.Base64.encodeBase64String(md5.digest("null".getBytes(Charsets.UTF_8)));
//        String ss = Hex.encodeHexString(md5bytes);


        String s1 = "POST\n" +
                "3o0RtwfPJbpSz6CE5H6S/w==\n" +
                "/api/whjz-mobileassist/homePage/getApprovalList1638b3f3b90c4829aabdaa7db94bfb3c";
        MessageDigest digest = MessageDigest.getInstance("MD5");
        byte[] content = digest.digest(s1.getBytes("UTF-8"));
        String computedSign = Hex.encodeHexString(content);
        String sign = "7f27af32cf0050ded9731713e814d178";

        JSONObject reqJsonObj = new JSONObject();
        reqJsonObj.put("aa", "bb");
        reqJsonObj.get("bb");
    }

}
